package plp.funcoo.expressions;

import plp.funcoo.environment.compilation.CompilationEnvironment;
import plp.funcoo.environment.compilation.Environment;
import plp.funcoo.environment.execution.ExecutionContext;
import plp.funcoo.environment.execution.ExecutionEnvironment;
import plp.funcoo.exceptions.ClassNotDeclared;
import plp.funcoo.exceptions.MethodAlreadDeclared;
import plp.funcoo.exceptions.MethodNotDeclared;
import plp.funcoo.exceptions.VarAlreadyDeclared;
import plp.funcoo.exceptions.VarNotDeclared;
import plp.funcoo.types.PrimitiveType;
import plp.funcoo.util.Type;
import plp.funcoo.value.IntegerValue;

public class ExpSum extends BinaryExpression {

	
	/**
	 * Constroi uma Expressao de Soma com as sub-expressoes especificadas.
	 * Assume-se que estas sub-expressoes resultam em <code>ValorInteiro</code> 
	 * quando avaliadas.
	 * @param esq Expressao da esquerda
	 * @param dir Expressao da direita
	 */
	public ExpSum(Expression lef, Expression right) {
		super(lef, right, "+");
	}

	/**
	 * Retorna o valor da Expressao de Soma
	 */
	@Override
	public ExecutionEnvironment evaluate(ExecutionEnvironment envi) throws VarNotDeclared, MethodNotDeclared, VarAlreadyDeclared, MethodAlreadDeclared {
		
		envi = getLeft().evaluate(envi); 
		IntegerValue l = (IntegerValue) ((ExecutionContext) envi).getValueAnalyzed();
		envi = getRight().evaluate(envi); 
		IntegerValue r = (IntegerValue) ((ExecutionContext) envi).getValueAnalyzed();
		((ExecutionContext) envi).setValueAnalyzed(new IntegerValue( l.getValue() + r.getValue() ));
		return envi;
	}

	@Override
	public Type getType(Environment envi) throws VarNotDeclared,
			ClassNotDeclared {
		if(getLeft().getType(envi).isFloat() || getRight().getType(envi).isFloat())
			return (Type) PrimitiveType.Type_FLOAT;
		else
			return (Type) PrimitiveType.Type_INT;
	}

	@Override
	protected boolean checkTypeTerminal(CompilationEnvironment envi) throws VarNotDeclared, ClassNotDeclared {
		
		return (getLeft().getType(envi).isInteger() || getLeft().getType(envi).isFloat()) && (getRight().getType(envi).isInteger() || getRight().getType(envi).isFloat());
	}

	public Expression makeCopy() {
		return new ExpSum(this.getLeft().makeCopy(), this.getRight().makeCopy());
	}

}
